/*
 * BncsMessage.h
 *
 *  Created on: Nov 18, 2008
 *      Author: nathan
 *
 * BncsMessage is the base class for all BNCS messages.
 * It uses Qt's implicitly shared data for good performance
 * when the message is read by multiple consumers simultaneously.
 */

#ifndef BNCSMESSAGE_H_
#define BNCSMESSAGE_H_

#include <QtCore>

/* The use of implicit sharing here is completely redundant, since
 * QVector is an implicitly shared class.  However, this demonstrates
 * a common idiom which should be used throughout the BncsMessage
 * subclasses, and extends to cases where the shared data is of
 * multiple types.
 *
 * The exposure of QSharedDataPointer<BncsMessageData> is intentional.
 * It would be annoying to both the programmer and the user of these
 * classes to write getters and setters for each member of each
 * data class.  Exposing this just lets the programmer access the
 * shared data directly.
 */

class BncsMessageData : public QSharedData
{
	public:
		QVector<quint8> data;
};

class BncsMessage
{
	public:
		static QByteArray readStringFrom(QDataStream& ds);
		static void writeStringTo(QDataStream& ds, QByteArray ba);
		static QVarLengthArray<quint8>& decodeStatString(QVarLengthArray<quint8>& coded);
		static QVarLengthArray<quint8>& encodeStatString(QVarLengthArray<quint8>& plain);

	private:
		int id;
		int size;

		QSharedDataPointer<BncsMessageData> d;

	public:
		BncsMessage(int id, int size)
		{
			this->id = id;
			this->size = size;

			d = new BncsMessageData();
			d->data.reserve(size);
		}

		virtual BncsMessage* clone()
		{
			BncsMessage* msg = new BncsMessage(id, size);
			*msg = *this;
			return msg;
		}

	public:
		virtual int id()
		{
			return id;
		}

		virtual int size()
		{
			return size;
		}

		virtual void readFrom(QDataStream& ds)
		{
			ds.readRawData(d->data.data(), size);
		}

		virtual void writeTo(QDataStream& ds)
		{
			ds.writeRawData(d->data.constData(), size);
		}

	public:
		QSharedDataPointer<BncsMessageData> getData()
		{
			return d;
		}
};

#endif /* BNCSMESSAGE_H_ */
